package com.huilian.tool.work.weixin.service.impl;

import com.alibaba.fastjson.JSON;
import com.huilian.tool.common.config.WorkWeiXinConfig;
import com.huilian.tool.common.utils.HuiLianHttpUtil;
import com.huilian.tool.common.utils.RestTemplateUtil;
import com.huilian.tool.redis.ToolRedisKey;
import com.huilian.tool.work.weixin.dto.*;
import com.huilian.tool.work.weixin.service.AuthorizeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author 少凡
 * @Date 2022-06-09 13:58
 * version 1.0
 */
@Slf4j
@Service
public class AuthorizeServiceImpl implements AuthorizeService {


    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Resource
    private RestTemplateUtil restTemplateUtil;
    @Resource
    private WorkWeiXinConfig workWeiXinConfig;
    @Autowired
    private RedisTemplate<String, Serializable> redisCacheTemplate;


    @Override
    public String getProviderAccessToken(String redisKey) {

        //先从缓存里获取服务商凭证
        //ToolRedisKey.WORK_WEI_XIN_PROVIDER_ACCESS_TOKEN
        Object providerAccessToken = redisCacheTemplate.opsForValue().get(redisKey);

        //如果缓存没有，就去线上获取
        if (ObjectUtils.isEmpty(providerAccessToken)) {
            String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token";
            Map<String, Object> params = new HashMap<>();
            params.put("corpid", workWeiXinConfig.getCorpid());
            params.put("provider_secret", workWeiXinConfig.getProviderSecret());

            ProviderAccessToken token = restTemplateUtil.unifyPost(url, params, ProviderAccessToken.class);

            if (!ObjectUtils.isEmpty(token.getProvider_access_token())) {
                log.info("从服务器获取providerAccessToken,保存到Redis:{}", token);
                redisCacheTemplate.opsForValue().set(ToolRedisKey.WORK_WEI_XIN_PROVIDER_ACCESS_TOKEN, token.getProvider_access_token(), token.getExpires_in(), TimeUnit.SECONDS);
            } else {
                log.error("ProviderAccessToken获取失败！");
                log.error("错误代码: " + token.getErrcode());
                log.error("错误信息: " + token.getErrmsg());
                return null;
            }

            return token.getProvider_access_token();
        }
        log.info("从Redis获取到providerAccessToken: " + providerAccessToken);
        return providerAccessToken.toString();
    }


    @Override
    public String getSuiteAccessToken(String suiteTicket) {

        //先从缓存里获取服务商凭证
        Object suiteAccessToken = redisCacheTemplate.opsForValue().get(ToolRedisKey.WORK_WEI_XIN_SUITE_ACCESS_TOKEN);

        //如果缓存没有，就去线上获取
        if (ObjectUtils.isEmpty(suiteAccessToken)) {

            Map<String, Object> params = new HashMap<>();
            params.put("suite_id", workWeiXinConfig.getSuiteId());
            params.put("suite_secret", workWeiXinConfig.getSuiteSecret());
            params.put("suite_ticket", suiteTicket);

            String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token";
            SuiteAccessToken token = restTemplateUtil.unifyPost(url, params, SuiteAccessToken.class);
            log.info("从服务器获取suiteAccessToken:{}", token);
            if (!ObjectUtils.isEmpty(token.getSuite_access_token())) {
                redisCacheTemplate.opsForValue().set(ToolRedisKey.WORK_WEI_XIN_SUITE_ACCESS_TOKEN, token.getSuite_access_token(), token.getExpires_in(), TimeUnit.SECONDS);
                return token.getSuite_access_token();
            } else {
                log.error("SuiteAccessToken获取失败！");
                log.error("错误代码： " + token.getErrcode());
                log.error("错误信息： " + token.getErrmsg());
                return null;
            }

        }
        log.info("从Redis获取到suiteAccessToken: " + suiteAccessToken);
        return suiteAccessToken.toString();
    }

    @Override
    public String getCorpAccessToken(String suiteTicket, String authCorpId, String permanentCode, Integer corpId) {
        //先从缓存里获取服务商凭证
        String key = ToolRedisKey.WORK_WEI_XIN_ACCESS_TOKEN + corpId;
        Object accessToken = redisCacheTemplate.opsForValue().get(key);
        //如果缓存没有，就去线上获取
        if (ObjectUtils.isEmpty(accessToken)) {
            //获取授权企业token域名
            String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token?suite_access_token=%s";
            Map<String, Object> params = new HashMap<>();
            params.put("auth_corpid", authCorpId);
            params.put("permanent_code", permanentCode);
            String suiteAccessToken = getSuiteAccessToken(suiteTicket);
            if (!ObjectUtils.isEmpty(suiteAccessToken)) {
                String url = String.format(access_token_url, suiteAccessToken);
                AccessToken token = restTemplateUtil.unifyPost(url, params, AccessToken.class);
                log.info("accessToken:{}", token);
                if (!ObjectUtils.isEmpty(token.getAccess_token())) {
                    redisCacheTemplate.opsForValue().set(key, token.getAccess_token(), token.getExpires_in(), TimeUnit.SECONDS);
                }
                return token.getAccess_token();
            } else {
                return null;
            }
        }
        log.info("accessToken:{}", accessToken);
        return accessToken.toString();

    }


    @Override
    public String getPreAuthCode(String suiteTicket) {
        //获取预授权码
        String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_pre_auth_code?suite_access_token=%s";
        String token = this.getSuiteAccessToken(suiteTicket);
        url = String.format(url, token);
        PreAuthCode preAuthCode = restTemplate.getForObject(url, PreAuthCode.class);
        log.info("preAuthCode:{}", preAuthCode);
        return preAuthCode.getPre_auth_code();
    }


    /**
     * 设置授权配置
     * 每次授权，都需要调用一次
     *
     * @param preAuthCode 这个预受权码，需要和授权同用
     * @return
     */
    @Override
    public String setSessionInfo(String suiteTicket, String preAuthCode, Integer authType) {

        String url = "https://qyapi.weixin.qq.com/cgi-bin/service/set_session_info?suite_access_token=%s";
        url = String.format(url, this.getSuiteAccessToken(suiteTicket));

        String[] idList = new String[10];
        idList[0] = workWeiXinConfig.getSuiteId();

        Map<String, Object> sessionInfo = new HashMap<>();
        sessionInfo.put("appid", idList);
        sessionInfo.put("auth_type", authType);
        Map<String, Object> params = new HashMap<>();
        params.put("pre_auth_code", preAuthCode);
        params.put("session_info", sessionInfo);

        return restTemplateUtil.unifyPost(url, params, String.class);

    }

    @Override
    public String authInstall(String redirectUrl, String suiteTicket, Integer authType) {

        StringBuilder url = new StringBuilder("https://open.work.weixin.qq.com/3rdapp/install");
        //获取预授权码
        String preAuthCode = getPreAuthCode((String) redisCacheTemplate.opsForValue().get(ToolRedisKey.WORK_WEI_XIN_SUITE_TICKET));

        Map<String, Object> params = new HashMap<>();
        params.put("suite_id", workWeiXinConfig.getSuiteId());
        params.put("pre_auth_code", preAuthCode);
        params.put("redirect_uri", redirectUrl);
        params.put("state", "STATE");

        //设置预授权
        String s = setSessionInfo(suiteTicket, preAuthCode, authType);

        return HuiLianHttpUtil.buildUrl(url.toString(), params);
    }

    /**
     * 获取企业永久授权码
     * 要获取企业永久授权码，需要在第三方网站安装应用，或在企业微信应用市场安装返回 临时授权码，才能够获取到
     * 临时授权码，会在授权成功时附加在redirect_uri中跳转回第三方服务商网站，或通过授权成功通知回调推送给服务商。长度为64至512个字节
     *
     * @param suiteTicket
     * @param authCode
     * @return
     */
    @Override
    public String getPermanentAuthCode(String suiteTicket, String authCode) {
        //获取企业永久授权码
        String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=%s";
        String suiteAccessToken = getSuiteAccessToken(suiteTicket);
        url = String.format(url, suiteAccessToken);
        Map<String, Object> params = new HashMap<>();
        params.put("auth_code", authCode);

        PermanentAuthCode code = restTemplateUtil.unifyPost(url, params, PermanentAuthCode.class);
        log.info(code.toString());

        log.info("默认永久授权码PermanentAuthCode储存在Redis,生产环境请保存在数据库里. " + code.getPermanent_code());
        System.out.println("auth_corpid: " + code.getAuth_corp_info().getCorpid());
        //TODO 实际应用中，这个永久授权码是要保存在数据库中！

        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend("iotBox-workWeChat-authCode", "iotBox-workWeChat-authCode.iotBoxWorkWeChatAuthCode", JSON.toJSONString(code), correlationData);
        //查询是否存在
//        WorkWxCorp entity = workWeiXinCorpDao.getInfoByAuthCorpId(code.getAuth_corp_info().getCorpid());
//        if (entity == null) {
//            entity = new WorkWxCorp();
//            entity.setCompanyName(code.getAuth_corp_info().getCorp_name());
//            entity.setAuthCorpId(code.getAuth_corp_info().getCorpid());
//            entity.setPermanentCode(code.getPermanent_code());
//            entity.setStatus(1);
//            workWeiXinCorpDao.insert(entity);
//        } else {
//            entity = new WorkWxCorp();
//            entity.setPermanentCode(code.getPermanent_code());
//            entity.setAuthCorpId(code.getAuth_corp_info().getCorpid());
//            entity.setStatus(1);
//            workWeiXinCorpDao.confirmAuth(entity);
//        }

        log.info("WORK_WEI_XIN_PERMANENT_AUTH_CODE", code.getPermanent_code());
        log.info("auth_corpid", code.getAuth_corp_info().getCorpid());
        return code.getPermanent_code();
    }


    @Override
    public String getAdminList(String suiteTicket, String authCorpId, String agentId) {
        StringBuilder url = new StringBuilder("https://qyapi.weixin.qq.com/cgi-bin/service/get_admin_list?suite_access_token=")
                .append(getSuiteAccessToken(suiteTicket));

        Map<String, Object> params = new HashMap<>();
        params.put("auth_corpid", authCorpId);
        params.put("agentid", agentId);
        return restTemplateUtil.unifyPost(url.toString(), params, String.class);
    }

    @Override
    public String getAuthInfo(String suiteTicket, String authCorpId, String permanentCode) {
        StringBuilder url = new StringBuilder("https://qyapi.weixin.qq.com/cgi-bin/service/get_auth_info?suite_access_token=")
                .append(getSuiteAccessToken(suiteTicket));

        Map<String, Object> params = new HashMap<>();
        params.put("auth_corpid", authCorpId);
        params.put("permanent_code", permanentCode);

        return restTemplateUtil.unifyPost(url.toString(), params, String.class);
    }

    @Override
    public String authLoginUrl(String redirectUrl, String scope, String state) {
        String url = new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize?appid=")
                .append(workWeiXinConfig.getSuiteId())
                .append("&redirect_uri=").append(redirectUrl)
                .append("&response_type=code&scope=").append(scope)
                .append("&state=").append(state).append("#wechat_redirect").toString();
        return url;
    }

    @Override
    public String getUserInfo3rd(String suiteTicket, String code) {
        String url = new StringBuilder("https://qyapi.weixin.qq.com/cgi-bin/service/getuserinfo3rd?")
                .append("suite_access_token=").append(getSuiteAccessToken(suiteTicket))
                .append("&code=").append(code).toString();
        return restTemplate.getForObject(url, String.class);
    }

    @Override
    public String getUserDetail3rd(String suiteTicket, String userTicket) {
        String url = new StringBuilder("https://qyapi.weixin.qq.com/cgi-bin/service/getuserdetail3rd?")
                .append("suite_access_token=").append(getSuiteAccessToken(suiteTicket)).toString();

        Map<String, Object> params = new HashMap<>();
        params.put("user_ticket", userTicket);
        return restTemplateUtil.unifyPost(url, params, String.class);
    }


}
